package UI;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.text.ParseException;
import java.util.logging.Level;
import java.util.logging.Logger;

import Logic.DSLogic;
import Logic.DSLogic.COMMAND_TYPE;
import Object.DSException;
import Task.DSTask;
import Task.DSTaskList;

//@author A0094762W
/**
 * DSUIController is the main communicator with the DSLogic component. It
 * implements the ActionListener interface and is dependent on the DSUI
 * and DSCommandListener class.
 */
public class DSUIController implements ActionListener {
	private static final int EXPAND_HIDE_ALL_VALUE = 0;

	private static final Logger _logger =
			Logger.getLogger(DSUIController.class.getName());

	private DSLogic _logic;
	private DSUI _userInterface;
	private DSCommandListener _commandListener;

	public DSUIController() throws IOException, ParseException {
		_logger.setLevel(Level.OFF);
		_logic = new DSLogic();
		_userInterface = new DSUI(this, _logic.getTaskListAsArray(),
															_logic.getAnimation(), _logic.getBackgroundNum());
		_commandListener = new DSCommandListener(_logic, _userInterface);
	}

	public void actionPerformed(ActionEvent e) {
		String command = _userInterface.obtainCommand();
		COMMAND_TYPE commandType = _logic.executeCommand(command);
		displayUIBasedOnCommand(commandType);
	}
	
	public DSTask getTaskFromTaskList(int index) {
		DSTaskList taskList = _logic.getTaskList();
		return taskList.get(index);
	}
	
	public int getTaskListSize() {
		DSTaskList taskList = _logic.getTaskList();
		return taskList.size();
	}
	
	private void displayUIBasedOnCommand(COMMAND_TYPE commandType) {
		if (isInvalidCommand(commandType)) {
			feedbackInvalidCommandToUser();
		} else {
			feedbackSuccessCommandToUser();
			updateDisplayForAppropriateCommand(commandType);
		}
	}

	private void feedbackSuccessCommandToUser() {
		_commandListener.feedbackMessage(true);
	}

	private void feedbackInvalidCommandToUser() {
		_commandListener.feedbackMessage(false);
	}

	private void updateDisplayForAppropriateCommand(COMMAND_TYPE commandType) {
		Object[] taskArray = _logic.getTaskListAsArray();
		switch (commandType) {
			case COMMAND_ADD :
				updateDisplayAfterAddCommand(taskArray);
				break;
			case COMMAND_DELETE :
				updateDisplayAfterDeleteCommand(taskArray);
				break;
			case COMMAND_EXPAND :
				updateDisplayAfterExpandOrHideCommand(taskArray);
				break;
			case COMMAND_EXCEPTION :
				retrieveAndDisplayException();
				break;
			case COMMAND_ANIMATION :
				setAnimationStatus();
				break;
			case COMMAND_BACKGROUND :
				changeBackground();
				break;
			case COMMAND_UPDATE :
				// Fallthrough
			case COMMAND_UNDO :
				// Fallthrough
			case COMMAND_DISPLAY :
				// Fallthrough
			case COMMAND_CLEAR :
				// Fallthrough
			case COMMAND_POSTPONE :
				// Fallthrough
			case COMMAND_SEARCH :
				// Fallthrough
			case COMMAND_DONE :
				// Fallthrough
			case COMMAND_UNDONE :
				// Fallthrough
			case COMMAND_OVERDUE :
				updateDisplay(taskArray);
				break;
			default:
				_logger.log(Level.SEVERE, "Error: Invalid Command Type");
				break;
		}
	}

	private boolean isInvalidCommand(COMMAND_TYPE commandType) {
		return commandType == COMMAND_TYPE.COMMAND_INVALID;
	}

	private void updateDisplay(Object[] taskArray) {
		_userInterface.updateUI(taskArray);
	}

	private void retrieveAndDisplayException() {
		String excepStr = _logic.getExceptionString();
		_userInterface.showMessage(excepStr);
	}

	private void updateDisplayAfterAddCommand(Object[] taskArray) {
		DSTask task = _logic.getLastChangedTask();
		_userInterface.addCommandUpdateUI(taskArray, task);
	}

	private void updateDisplayAfterDeleteCommand(Object[] taskArray) {
		DSTask task = _logic.getLastChangedTask();
		_userInterface.deleteCommandUpdateUI(taskArray, task);
	}
	
	private void setAnimationStatus() {
		boolean newAnimationStatus = _userInterface.setAnimationStatus();
		try {
			_logic.setAnimation(newAnimationStatus);
		} catch (DSException e) {
			System.out.println("Saving of animation not successful: " + e);
			e.printStackTrace();
		}
	}
	
	private void changeBackground() {
		int backgroundNum = _userInterface.changeBackground();
		try {
			_logic.setBackgroundNum(backgroundNum);
		} catch (DSException e) {
			System.out.println("Saving of backgroundNum not successful: " + e);
			e.printStackTrace();
		}
	}
	
	private void updateDisplayAfterExpandOrHideCommand(Object[] taskArray) {
		int expandStatus = _logic.getExpandStatus();
		if (isHideOrExpandIndividual(expandStatus)) {
			DSTask task = findTaskToExpandOrHide(taskArray, expandStatus);
			_userInterface.expandTaskInUI(expandStatus, task);
		} else {
			_userInterface.expandTaskInUI(expandStatus, null);
		}
	}

	private DSTask findTaskToExpandOrHide(Object[] taskArray, int expandStatus) {
		return (DSTask) taskArray[expandStatus - 1];
	}

	private boolean isHideOrExpandIndividual(int expandStatus) {
		return expandStatus > EXPAND_HIDE_ALL_VALUE;
	}
}